package service

import (
	"context"
	"fmt"
	"github.com/xxl-job/xxl-job-executor-go"
	"gorm.io/gorm"
	"myai/core/types"
	logger2 "myai/logger"
	"myai/service/crawler"
	"myai/store/model"
	"myai/utils"
	"time"
)

var log = logger2.GetLogger()

type XXLJobExecutor struct {
	executor xxl.Executor
	db       *gorm.DB
	// 爬虫
	cms *crawler.CrawlersManagerService
}

func NewXXLJobExecutor(config *types.AppConfig, db *gorm.DB, cms *crawler.CrawlersManagerService) *XXLJobExecutor {
	if !config.XXLConfig.Enabled {
		log.Info("XXL-JOB Service is disabled")
		return nil
	}
	exec := xxl.NewExecutor(
		xxl.ServerAddr(config.XXLConfig.ServerAddr),     // 调度中心地址
		xxl.AccessToken(config.XXLConfig.AccessToken),   // 请求令牌（默认为空）
		xxl.ExecutorIp(config.XXLConfig.ExecutorIp),     // 可自动获取
		xxl.ExecutorPort(config.XXLConfig.ExecutorPort), // 默认9999（非必填）
		xxl.RegistryKey(config.XXLConfig.RegistryKey),   // 执行器名称
		xxl.SetLogger(&customLogger{}),                  // 自定义日志
	)
	exec.Init()
	return &XXLJobExecutor{executor: exec, db: db, cms: cms}
}

func (e *XXLJobExecutor) Run() error {
	e.executor.RegTask("ClearOrders", e.ClearOrders)
	e.executor.RegTask("ResetVipPower", e.ResetVipPower)
	e.executor.RegTask("ResetUserPower", e.ResetUserPower)
	e.executor.RegTask("CrawlerHotData", e.CrawlerHotData)
	return e.executor.Run()
}

func (e *XXLJobExecutor) CrawlerHotData(ctx context.Context, param *xxl.RunReq) (msg string) {
	start := time.Now()
	e.cms.ExecCrawler()
	elapsed := time.Now().Sub(start)
	log.Infof("爬虫耗时：%s\v", elapsed)
	return "success"
}

// ClearOrders 清理未支付的订单，如果没有抛出异常则表示执行成功
func (e *XXLJobExecutor) ClearOrders(ctx context.Context, param *xxl.RunReq) (msg string) {
	log.Info("执行清理未支付订单...")
	var sysConfig model.Config
	res := e.db.Where("marker", "system").First(&sysConfig)
	if res.Error != nil {
		return "查询系统配置出错：" + res.Error.Error()
	}

	var config types.SystemConfig
	err := utils.JsonDecode(sysConfig.Config, &config)
	if err != nil {
		return "解码系统配置数据出错：" + err.Error()
	}

	// 默认未支付订单的生命周期为 30 分钟
	if config.OrderPayTimeout == 0 {
		config.OrderPayTimeout = 1800
	}
	timeout := time.Now().Unix() - int64(config.OrderPayTimeout)
	start := utils.Stamp2str(timeout)
	res = e.db.Unscoped().Where("status in ? and created_at < ?",
		[]types.OrderStatus{types.OrderNotPaid, types.OrderScanned}, start).Delete(&model.Order{})
	log.Infof("删除订单成功，删除 %d 条订单。", res.RowsAffected)
	return "success"
}

// ResetVipPower 重置VIP会员算力
// 自动将 VIP 会员的算力补充到每月的最大值
func (e *XXLJobExecutor) ResetVipPower(ctx context.Context, param *xxl.RunReq) (msg string) {
	log.Info("开始进行月底账号盘点...")
	/*var users []model.User
	res := e.db.Where("vip = ?", 1).First(&users)
	if res.Error != nil {
		return "没有VIP用户"
	}

	var sysConfig model.Config
	res = e.db.Where("marker", "system").First(&sysConfig)
	if res.Error != nil {
		return "获取系统配置出现错误：" + res.Error.Error()
	}

	var config types.SystemConfig
	err := utils.JsonDecode(sysConfig.Config, &config)
	if err != nil {
		return "解码系统配置出现错误：" + err.Error()
	}

	// 获取本月初时间
	currentTime := time.Now()
	year, month, _ := currentTime.Date()
	firstOfMonth := time.Date(year, month, 1, 0, 0, 0, 0, currentTime.Location()).Unix()
	for _, u := range users {
		// 账号到期直接清零
		if u.ExpiredTime <= currentTime.Unix() {
			log.Infof("账号过期：%s", u.Username)
			u.Vip = false
		} else {
			// 如果该用户当月有充值点卡，则将点卡中未用完的点数结余到下个月
			var orders []model.Order
			e.db.Where("user_id = ? and pay_time > ?", u.Id, firstOfMonth).Find(&orders)
			for _, o := range orders {
				var remark types.OrderRemark
				err = utils.JsonDecode(o.Remark, &remark)
				if err != nil {
					continue
				}
				// 会员续费
				if remark.Days > 0 {
					continue
				}
			}
		}
	}*/

	return "success"
}

// ResetUserPower 系统每日派发算力
func (e *XXLJobExecutor) ResetUserPower(ctx context.Context, param *xxl.RunReq) (msg string) {
	log.Info("今日算力派发开始：", time.Now())
	var users []model.User
	res := e.db.Where("status", 1).Find(&users)
	if res.Error != nil {
		return "没有匹配的用户"
	}

	var sysConfig model.Config
	res = e.db.Where("marker", "system").First(&sysConfig)
	if res.Error != nil {
		return "获取系统配置出错：" + res.Error.Error()
	}

	var config types.SystemConfig
	err := utils.JsonDecode(sysConfig.Config, &config)
	if err != nil {
		return "解码系统配置数据出错：" + err.Error()
	}

	// 判断每日赠送的算力是否小于 0，如果小于0 就不用赠送了
	if config.DailyPower <= 0 {
		return "success"
	}

	var counter = 0
	var totalPower = 0
	for _, u := range users {
		// 判断当前用户的算力 是不是 大于 赠送的算力，如果大于就跳过
		if u.Power >= config.DailyPower {
			continue
		}
		// 系统赠送算力 减去 用户算力 就是每日赠送算力
		var power = config.DailyPower - u.Power
		tx := e.db.Model(&model.User{}).Where("id", u.Id).UpdateColumn("power", gorm.Expr("power + ?", power))
		// 记录算力充值日志
		if tx.Error == nil {
			var user model.User
			e.db.Where("id", u.Id).First(&user)
			e.db.Create(&model.PowerLog{
				UserId:    u.Id,
				Username:  u.Username,
				Type:      types.PowerGift,
				Amount:    power,
				Balance:   user.Power,
				Model:     "系统赠送",
				Remark:    fmt.Sprintf("系统每日算力派发，今日额度：%d", config.DailyPower),
				Mark:      types.PowerAdd,
				CreatedAt: time.Now(),
			})
		}
		counter++
		totalPower += power
	}
	log.Infof("今日算力派发结束！累计派发 %d 人，累计派发算力：%d", counter, totalPower)
	return "success"
}

type customLogger struct {
}

func (l *customLogger) Info(format string, a ...interface{}) {
	log.Debugf(format, a...)
}

func (l *customLogger) Error(format string, a ...interface{}) {
	log.Errorf(format, a...)
}
